Skip to content

feat(threads): thread drawer, thread browser, live reply counts, and unread badges#564

Open
Just-Insane wants to merge 5 commits intoSableClient:devfrom
Just-Insane:feat/thread-enhancements
Open

feat(threads): thread drawer, thread browser, live reply counts, and unread badges#564
Just-Insane wants to merge 5 commits intoSableClient:devfrom
Just-Insane:feat/thread-enhancements

Conversation

@Just-Insane
Copy link
Copy Markdown
Contributor

@Just-Insane Just-Insane commented Mar 28, 2026

📝 Docs: Already live at Threads — Sable Docs — no separate docs PR needed.


Description

Expands Matrix thread support with a full thread drawer, server-side thread browser, live reply counts, unread badges, and several UX fixes.

ThreadDrawer

  • Slide-in drawer for reading and replying in threads without leaving the main room
  • Thread root message shown at top with full reply history below
  • Up-arrow edit-last-message: pressing ↑ in the thread input edits the user's last own message in that thread
  • Reactions add/remove trigger immediate re-renders without manual refresh (handles the fact that reaction events carry m.relates_to.event_id not threadRootId directly — fetches target event to check thread membership)
  • Thread root message box sized to content with maxHeight: 200px to avoid dead whitespace on short messages

ThreadBrowser

  • Lists all threads in the room; calls room.fetchRoomThreads() on mount to load threads beyond the local timeline window
  • Load-more button when the server has additional thread pages
  • Each thread preview shows sender avatar, display name, reply count, and last message body with ellipsis truncation
  • Jump button navigates to the thread root in the main timeline (via useRoomNavigate) instead of re-opening the drawer
  • Thread unread badges on each preview item via room.getThreadUnreadNotificationCount()

ThreadReplyChip (main timeline)

  • Shows unread badge for threads with unseen replies via room.getThreadUnreadNotificationCount()

Thread button (RoomViewHeader)

  • If a thread drawer is open, button closes the drawer and opens the thread browser (allows going from a single thread to the full list)
  • If no thread is open, button toggles the thread browser as before
  • aria-pressed reflects both thread browser state and open thread drawer

Fixes #

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

AI disclosure:

  • Partially AI assisted (clarify which code was AI assisted and briefly explain what it does)
  • Fully AI generated (explain what all the generated code does in moderate detail)

ThreadDrawer/ThreadBrowser/thread-chip iterations were partially AI assisted; I reviewed and adjusted logic for timeline processing, thread loading, and event rendering behavior.

@Just-Insane Just-Insane force-pushed the feat/thread-enhancements branch from 29282cb to 740e69c Compare March 28, 2026 02:33
@Just-Insane Just-Insane changed the title feat(threads): add full thread support with ThreadDrawer and ThreadBrowser feat: add Matrix thread support Mar 28, 2026
@Just-Insane Just-Insane marked this pull request as ready for review March 28, 2026 02:48
@Just-Insane Just-Insane requested review from 7w1 and hazre as code owners March 28, 2026 02:48
Copilot AI review requested due to automatic review settings March 28, 2026 02:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end Matrix thread support across the room timeline: a thread drawer for reading/replying in-thread, a thread browser listing room threads (with pagination), and live reply/unread indicators, backed by Matrix SDK threadSupport.

Changes:

  • Enable SDK thread tracking by passing threadSupport: true to startClient (classic + sliding sync).
  • Introduce shared edit-mode hook (useMessageEdit) and wire it through RoomTimeline/timeline actions and ThreadDrawer.
  • Implement thread UI primitives: ThreadDrawer ported to the shared timeline rendering pipeline, ThreadBrowser backed by /threads + pagination/backfill, and live reply/unread badges on timeline thread chips.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/client/initMatrix.ts Enables Matrix SDK thread support in both classic and sliding sync start paths.
src/app/hooks/useMessageEdit.ts New hook to centralize edit-mode state/reset/focus behavior for composers.
src/app/hooks/timeline/useTimelineEventRenderer.tsx Adds live thread reply/unread chip updates; supports suppressing thread chip/reply headers inside drawer.
src/app/hooks/timeline/useTimelineActions.ts Refactors timeline actions to accept shared handleEdit instead of owning edit state.
src/app/hooks/timeline/useProcessedTimeline.ts Adds skipThreadFilter to allow processing thread timelines without filtering out replies.
src/app/features/room/ThreadDrawer.tsx Reworks thread drawer to use shared timeline processing/rendering; adds sequential loading/backfill and edit-last-message support.
src/app/features/room/ThreadBrowser.tsx Adds server-backed thread list with load-more pagination, root-event backfill, and unread badges.
src/app/features/room/RoomTimeline.tsx Adopts useMessageEdit and passes handleEdit into timeline actions.
src/app/features/common-settings/developer-tools/DevelopTools.tsx Adds thread diagnostics + “fetch from server” action for debugging thread state.
.changeset/feat-thread-enhancements.md Declares a minor release note for thread support features.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Just-Insane added a commit to Just-Insane/Sable that referenced this pull request Mar 28, 2026
- useTimelineEventRenderer.tsx: Use Math.max(thread.length, replyEvents.length) to avoid undercounting replies when only a subset of events is loaded locally.
- ThreadBrowser.tsx: Use Math.max(thread.length, localReplyCount) to show correct total even for threads whose timeline hasn't been fully paginated.
- ThreadDrawer.tsx: Align showClientUrlPreview logic with RoomTimeline: require both clientUrlPreview AND encClientUrlPreview in encrypted rooms.
- useMessageEdit.ts: Minor wording: 'never stales' → 'never goes stale'.
Just-Insane added a commit to Just-Insane/Sable that referenced this pull request Mar 28, 2026
- useTimelineEventRenderer.tsx: Use Math.max(thread.length, replyEvents.length) to avoid undercounting replies when only a subset of events is loaded locally.
- ThreadBrowser.tsx: Use Math.max(thread.length, localReplyCount) to show correct total even for threads whose timeline hasn't been fully paginated.
- ThreadDrawer.tsx: Align showClientUrlPreview logic with RoomTimeline: require both clientUrlPreview AND encClientUrlPreview in encrypted rooms.
- useMessageEdit.ts: Minor wording: 'never stales' → 'never goes stale'.
@Just-Insane Just-Insane changed the title feat: add Matrix thread support feat: Update Matrix threads Mar 28, 2026
@Just-Insane Just-Insane force-pushed the feat/thread-enhancements branch 3 times, most recently from a0e4ef7 to b595e6b Compare March 29, 2026 18:31
Fired on every room message, causing N×chip re-renders and O(n_events)
scans per message when N threads are visible. ThreadEvent.NewReply/Update
and RoomEvent.Redaction already cover the relevant updates.
@Just-Insane Just-Insane force-pushed the feat/thread-enhancements branch from d3520ef to 6709a58 Compare March 30, 2026 12:49
@Just-Insane Just-Insane changed the title feat: Update Matrix threads feat(threads): thread drawer, thread browser, live reply counts, and unread badges Mar 30, 2026
@7w1
Copy link
Copy Markdown
Member

7w1 commented Mar 31, 2026

Proper threads! Yay! only thing I noticed is some styling with scrollbars in the thread drawer:
image

!!threadObjForLoading && !threadObjForLoading.initialEventsFetched && replyEvents.length === 0;

replyEventsRef.current = replyEvents;
// Automatically paginate backwards until all older replies are loaded.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably shouldn't be paginating backwards until all replies are loaded? If its a huge thread with like 2000 replies we should just paginate when the user scrolls up, not automatically, unless I'm misunderstanding something

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants